#include "command_option.hh"
#include <iostream>
#include <fstream>
#include "version.hh"
#include "../corelib/util/string_util.hh"
#include "../corelib/util/os_util.hh"
#include "module_manager.hh"

#ifndef WIN32
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#endif // WIN32

using namespace cxxopts;

static const char* kratos_logo =
"\n"
"  __                      __                    \n"
" |  | _________ _____   _/  |_   ____    ______ \n"
" |  |/ /\\_  __ \\\\__  \\  \\   __\\ /  _ \\  /  ___/\n"
" |    <  |  | \\/ / __ \\_ |  |  (  <_> ) \\___ \\ \n"
" |__|_ \\ |__|   (____  / |__|   \\____/  /____ >  \n"
"      \\/             \\/                     \\/  \n"
"\n";

namespace kratos { namespace engine {
CommandOptions::CommandOptions() {
    configFilePath_ = "engine.cfg";
    pluginPath_ = "module";
    serviceName_ = "engine";
    pidFilePath_ = "./";
    startAsService_ = false;
    debug_ = false;
    debugLogType_ = kratos::corelib::AppenderType::File;
    frame_ = 60;
}

CommandOptions::~CommandOptions() {
}

bool CommandOptions::load(int argc, const char** argv) {
    Options options("Engine", kratos_logo);
    options.add_options()
        ("c,config", "Config file, .cfg", value<std::string>())
        ("d,daemon", "Start as service")
        ("n,name", "Service name", value<std::string>())
        ("plugins", "Plugins path", value<std::string>())
        ("debug", "Debug mode")
        ("debug-logtype", "Debug log type", value<std::string>())
        ("pid", "PID file path", value<std::string>())
        ("f,frame", "The maximum frequency of main cycle, frame/second", value<int>())
#ifndef WIN32
        ("s,stop", "Service name or PID file path", value<std::string>())
#endif // WIN32
        ("h,help", "help");
    auto result = options.parse(argc, argv);
#ifndef WIN32
    if (result["stop"].count()) {
        auto pidFilePath = result["stop"].as<std::string>();
        if (!corelib::StringUtil::endWith(pidFilePath, ".pid")) {
            pidFilePath += ".pid";
        }
        std::ifstream ifs;
        ifs.open(pidFilePath.c_str(), std::ios::in);
        if (!ifs) {
            std::cerr << "PID file not found:" << pidFilePath << std::endl;
            return false;
        }
        std::string temp;
        ifs >> temp;
        auto pid = std::stoi(temp);
        ::kill(pid, SIGQUIT);
        _exit(0);
    }
#endif // WIN32
    if (result["config"].count()) {
        configFilePath_ = result["config"].as<std::string>();
    }
    if (result["daemon"].count()) {
        startAsService_ = true;
    }
    if (result["name"].count()) {
        serviceName_ = result["name"].as<std::string>();
    } else {
        //if (startAsService_) {
        //    std::cerr << "Need a service name when start with options '-d,--daemon'" << std::endl;
        //    return false;
        //}
    }
    if (result["plugins"].count()) {
        pluginPath_ = result["plugins"].as<std::string>();
        if (!corelib::StringUtil::endWith(pluginPath_, "/")) {
            pluginPath_ += "/";
        }
    }
    if (result["help"].count()) {
        std::cout << options.help() << std::endl;
        std::cout << getVersion() << std::endl;
        return false;
    }
    if (result["pid"].count()) {
        pidFilePath_ = result["pid"].as<std::string>();
        if (!corelib::StringUtil::endWith(pidFilePath_, "/")) {
            pidFilePath_ += "/";
        }
    }
    if (result["debug"].count()) {
        debug_ = true;
        corelib::OS::getFiles(pluginPath_, MODULE_SUFFIX, configFileNames_);
        for (auto& name : configFileNames_) {
            name = corelib::StringUtil::remove(name, MODULE_SUFFIX);
            name += ".cfg";
        }
        if (result["debug-logtype"].count()) {
            auto value = result["debug-logtype"].as<std::string>();
            if (value == "console") {
                debugLogType_ = kratos::corelib::AppenderType::Console;
            } else if (value == "file") {
                debugLogType_ = kratos::corelib::AppenderType::File;
            } else {
                std::cerr << "unrecognized log type:" << value << std::endl;
                return false;
            }
        }
    }
    if (result["frame"].count()) {
        frame_ = result["frame"].as<int>();
    }
    return true;
}

const std::string & CommandOptions::getConfigFilePath() const {
    return configFilePath_;
}

bool CommandOptions::isStartAsService() const {
    return startAsService_;
}

const std::string & CommandOptions::getServiceName() const {
    return serviceName_;
}

const std::string & CommandOptions::getPluginPath() const {
    return pluginPath_;
}

const std::string & CommandOptions::getPIDFilePath() const {
    return pidFilePath_;
}

bool CommandOptions::isDebug() const {
    return debug_;
}

const CommandOptions::StringVector & CommandOptions::getConfigFileNames() const {
    return configFileNames_;
}

kratos::corelib::AppenderType CommandOptions::getAppenderType() {
    return debugLogType_;
}

int CommandOptions::getFrame() {
    return frame_;
}

}}
